package com.minhang.config.security.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.minhang.domain.Employee;
import com.minhang.mapper.EmployeeMapper;
import com.minhang.utils.result.ResultCode;
import com.minhang.utils.result.ResultGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * jwt拦截
 *
 * @author rookie
 */
@Slf4j
@Component
public class JwtFilter extends OncePerRequestFilter {


    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private EmployeeMapper employeeMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        // 1、从请求头中获取token
        String token = httpServletRequest.getHeader("token");
        // 2、判断 token 是否存在
        if (token == null || "null".equals(token) || "".equals(token)) {
            log.error("未登录");
            //解析token
            SecurityContextHolder.getContext().setAuthentication(null);
        } else {
            int expired = -2;
            int remaining = 2000;
            //判断时间
            long expire = redisTemplate.getExpire("OA:token:" + token);

            if ((int) expire != expired) {
                log.info("成功");
                Object emp = redisTemplate.opsForValue().get("OA:token:" + token);
                String stringEmp = JSONObject.toJSONString(emp);
                //解析出来员工对象
                Map<String, String> map = JSON.parseObject(stringEmp, Map.class);
                Employee employee = employeeMapper.selectById(new Integer(map.get("id")));
                if (!employee.getPwd().equals(map.get("pwd"))){
                    // 这里可以自定义 抛出 token 异常
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    PrintWriter writer = httpServletResponse.getWriter();
                    writer.write(new ObjectMapper().writeValueAsString(ResultGenerator.genFailResult("密码已修改,请重新登录", ResultCode.UNAUTHORIZED)));
                    writer.flush();
                    writer.close();
                    return;
                }
                //解析token
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(employee, null, employee.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
                //设置为已登录
                SecurityContextHolder.getContext().setAuthentication(authentication);
                if ((int) expire < remaining) {
                    //续期
                    redisTemplate.expire("OA:token:" + token, 120, TimeUnit.MINUTES);
                }
            } else {
                log.error("token已过期，请重新登录");
                // 这里可以自定义 抛出 token 异常
                httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter writer = httpServletResponse.getWriter();
                writer.write(new ObjectMapper().writeValueAsString(ResultGenerator.genFailResult("登录已过期", ResultCode.UNAUTHORIZED)));
                writer.flush();
                writer.close();
                return;
            }
        }
        //继续执行
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

}
